#include "stdafx.h"
#include "MyExpat.h"
#include "Test.h"
#include "TileDownloader.h"


using namespace std;



extern GPXRoot parseResult = GPXRoot();

class ZuParsendeDaten
{
public:
	int tiefe;
	int maxTiefe;
	bool metadata;
	bool time;
	bool trkSeg;
	bool track;
	bool name;
	bool ele;
	bool trkPt;
	bool wpt;
	TrkPtType tempPt;
	TRKType tempTrack;
	TRKSegType tempTrkSeg;
	WPTType tempWaypoint;
	ZuParsendeDaten()
		:
		tiefe(0), maxTiefe(-1)
	{
		wpt = false;
		metadata = false;
		time = false;
		trkSeg = false;
		track = false;
		name = false;
		ele = false;
		trkPt = false;
	}
};

void startElement(void *userData, const char *name, const char **atts)
{
	ZuParsendeDaten* daten = (ZuParsendeDaten*) userData;
	string theName = name;
	daten->tiefe++;
	if( daten->tiefe > daten->maxTiefe ) daten->maxTiefe = daten->tiefe;
	if(theName == "gpx") {
		if( atts )
		{
			while( *atts )
			{
				string key   = *atts++;
				const char* value = *atts++;

				if(key == "creator") {
					parseResult.setCreator(value);
				} else if (key == "version") {
					parseResult.setVersion(value);
				}
			}
		}
	} else if(theName=="metadata") { // if gpx

		daten->metadata = true;
		while( *atts )
		{
			string key   = *atts++;
			const char* value = *atts++;



		}

		// if metadata
	} 

	else if(theName == "trkpt") {
		daten->trkPt = true;
		daten->tempPt =   TrkPtType();

		if(atts) {
			while( *atts )
			{
				string key   = *atts++;
				const char* value = *atts++;

				if(key == "lat") {
					if(daten->trkPt  && !daten->wpt) {
					daten->tempPt.setLat(atof(value));
					} 
					if(daten->wpt && !daten->trkPt) {
					daten->tempWaypoint.setLat(atof(value));
					}
				}
					
					
					else if(key == "lon") {

						if(daten->trkPt && !daten->wpt) {
					daten->tempPt.setLon(atof(value));
				}
						if(daten->wpt && !daten->trkPt) {
							daten->tempWaypoint.setLon(atof(value));
						}
			}
			}



		}

	}
	else if(theName == "link") {
		if(atts) {
			while( *atts )
			{
				string key   = *atts++;
				const char* value = *atts++;

				if(key == "href") {
					parseResult.setLink(value);
				}
			}
		}// if link
	} else if(theName == "bounds") {
		if(atts) {
			while( *atts )
			{
				string key   = *atts++;
				const char* value = *atts++;

				if(key == "maxlat") {
					parseResult.setMaxlat(atof(value));
				} else if(key == "maxlon") {
					parseResult.setMaxlon(atof(value));
				} else if (key =="minlon") {
					parseResult.setMinlon(atof(value));
				} else if(key =="minlat") {
					parseResult.setMinlat(atof(value));
				}
			}
		}
	}
	else if(theName =="ele") {
		daten->ele = true;


	} 	
	else if(theName =="time")	{
		daten->time = true;

	}


	else if(theName =="trk" ) {
		daten->track = true;
		TRKType track = TRKType();
		daten->tempTrack = track;


	} else if(theName == "name") {
		daten->name = true;
	} else if(theName == "trkseg") {
		daten->trkSeg = true;
		daten->tempTrkSeg = TRKSegType();




	} else if(theName == "wpt") {
		daten->wpt = true;
		WPTType waypoint = WPTType();
		daten->tempWaypoint = waypoint;
	} 
}






void endElement(void *userData, const char *name)
{


	ZuParsendeDaten* daten = (ZuParsendeDaten*) userData;
	daten->tiefe--;

	string theName = name;

	if(theName == "metadata") {
		daten->metadata = false;
	} else if(theName == "time") {
		daten->time = false;
	} else if(theName == "trk") {
		parseResult.tracks.push_back(daten->tempTrack);
		daten->track = false;
	} else if(theName == "name") {
		daten->name = false;
	} else if(theName == "trkseg") {
		daten->tempTrack.trkSegments.push_back(daten->tempTrkSeg);
		daten->trkSeg = false;

	} else if(theName =="trkpt") {

		daten->tempTrkSeg.points.push_back(daten->tempPt);
		daten->trkPt = false;

	} else if(theName =="ele") {
		daten->ele = false;
	} else if(theName =="wpt") {
		parseResult.waypoints.push_back(daten->tempWaypoint);
		daten->wpt = false;
	}



}

void characterDataHandler(void *userData, const XML_Char *value, int len)
{	ZuParsendeDaten* daten = (ZuParsendeDaten*) userData;
string s(value,value+len);
if(daten->time && !daten->trkPt) {
	parseResult.setTime(s);

	s.clear();
} else if(daten->name && daten->track) {
	daten->tempTrack.setName(s);

	s.clear();

} else if(daten->trkPt && daten->time ) {

	daten->tempPt.setTime(s); 	
	s.clear();

} else if(daten->trkPt && daten->ele)
{

	const char* temp = s.c_str();
	daten->tempPt.setEle(atof(temp));

	s.clear();
}


}
class Datei
{
	FILE* fp;
public:
	Datei( const char* dateiName, const char* mode )
		:
		fp( fopen(dateiName, mode) )
	{
	}

	~Datei()
	{
		if( fp ) fclose(fp);
	}

	FILE* GetFileHandle()
	{
		return fp;
	}
};

class XMLParser
{
	XML_Parser parserHandle;
public:
	XMLParser()
		:
		parserHandle( XML_ParserCreate(NULL) )
	{
	}

	~XMLParser()
	{
		XML_ParserFree(parserHandle);
	}
	void SetElementHandler(XML_StartElementHandler start, XML_EndElementHandler end )
	{
		XML_SetElementHandler( parserHandle, startElement, endElement);
	}

	XML_Parser Handle()
	{
		return parserHandle;
	}
	static void startElementNichtStatisch(void *userData, const char *name, const char **atts)
	{
	}

	void ParseFile( const char* fileName, XML_StartElementHandler start, XML_EndElementHandler end )
	{
		SetElementHandler( startElementNichtStatisch, end);
		XML_SetCharacterDataHandler( parserHandle, characterDataHandler ); 

		Datei datei(fileName, "r");
		if( datei.GetFileHandle() ) 
		{
			int done;
			do // loop over whole file content
			{
				const unsigned BUFFER_SIZE = 1000000;
				char buf[BUFFER_SIZE ];
				size_t len = fread(buf, 1, sizeof(buf), datei.GetFileHandle() );// read chunk of data
				done = len < sizeof(buf); // end of file reached
				if (!XML_Parse(parserHandle, buf, (int)len, done)) 
				{  // a parse error occured:
					fprintf( stderr, "%s at line %d\n",  
						XML_ErrorString(XML_GetErrorCode(parserHandle)),
						XML_GetCurrentLineNumber(parserHandle));
					//fclose(fp);
					done = 1;// quit: TODO indicate error somehow
				}
			} while (!done);
			//fclose(fp);
		}
	}
};


int main( int argc, const char* argv[] )
{
	char fileName[] = "geradelt.gpx";

	ZuParsendeDaten daten;



	XMLParser parser;
	XML_SetUserData( parser.Handle(), &daten );
	parser.ParseFile( fileName, startElement, endElement);


	double* cornerPTest = new double[4];
	parseResult.tracks.at(0).getCornerPoints(cornerPTest);

	TileDownloader downloader = TileDownloader();
	downloader.downloadMapTiles(cornerPTest, 12);


	cornerPTest = nullptr;
	int i;
	cin >> i;

	

	return 0;
}

